/**
 * @brief SPI-Flash 驱动
 * @author 张勇 / 2020-05-13
 */

#pragma once

#include "mcu.h"
#include "unidrv/ffsystem.h"

// FLASH 芯片型号 ID 列表
typedef enum _ftid {
    FTID_NULL     = 0,
    FTID_W25Q80   = 0xEF13, // W25Q80  
    FTID_W25Q16   = 0xEF14, // W25Q16  
    FTID_W25Q32   = 0xEF15, // W25Q32  
    FTID_W25Q64   = 0xEF16, // W25Q64  
    FTID_W25Q128  = 0xEF17, // W25Q128 
    FTID_W25Q256  = 0xEF18, // W25Q256 
    FTID_BY25Q64  = 0x6816, // BY25Q64 
    FTID_BY25Q128 = 0x6817, // BY25Q128
    FTID_BY25Q256 = 0x6818, // BY25Q256
    FTID_NM25Q64  = 0x5216, // NM25Q64 
    FTID_NM25Q128 = 0x5217, // NM25Q128
} ftid_t;

// FLASH 芯片型号 JEDEC ID(24位) 列表
typedef enum _ft_jedec_id {
    JEDEC_MT25Q = 0x20BB22,
} ft_jedec_id_t;

typedef struct _mcu_spiflash {
    mcu_spi_t *spi;                 ///< SPI 接口
    std_err_t (*cs)(bool selected); ///< 片选控制回调函数: 是否选通本芯片
    ftid_t typeid;                  ///< FLASH 芯片型号 ID
    uint32_t pagesize;              ///< 写入时的页大小(字节数)
    uint32_t blocksize;             ///< 擦除时的块大小(字节数)
    uint32_t blockcount;            ///< 总共有多少个块
    uint8_t *blockbuf;              ///< 块缓存指针
    ft_jedec_id_t jedecid;          ///< FLASH 芯片型号 Jedec ID
} mcu_spiflash_t;


#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief 初始化 Flash
 */
std_err_t unidrv_spiflash_init(mcu_spiflash_t *dev);

/**
 * @brief  读取SPI FLASH
 * @note   在指定地址开始读取指定长度的数据
 * @param  pbuf    : 数据存储区
 * @param  addr    : 开始读取的地址(最大32bit)
 * @param  datalen : 要读取的字节数(最大65535)
 * @retval 无
 */
void unidrv_spiflash_read(mcu_spiflash_t *dev, uint8_t *pbuf, uint32_t addr, uint32_t datalen);

/**
 * @brief  写SPI FLASH
 * @note   在指定地址开始写入指定长度的数据 , 该函数带擦除操作!
 *         SPI FLASH 一般是: 256个字节为一个Page, 4Kbytes为一个Sector, 16个扇区为1个Block
 *         擦除的最小单位为Sector.
 * @param  pbuf    : 数据存储区
 * @param  addr    : 开始写入的地址(最大32bit)
 * @param  datalen : 要写入的字节数(最大65535)
 * @retval 无
 */
void unidrv_spiflash_write(mcu_spiflash_t *dev, const void *pbuf, uint32_t addr, uint32_t datalen);

/**
 * @brief 擦除整个芯片
 * @note  等待时间超长...
 */
void unidrv_spiflash_erase_chip(mcu_spiflash_t *dev);

/**
 * @brief  擦除一个扇区
 * @note   注意,这里是扇区地址,不是字节地址!!
 *         擦除一个扇区的最少时间:150ms
 * @param  saddr : 扇区地址 根据实际容量设置
 * @retval 无
 */
void unidrv_spiflash_erase_sector(mcu_spiflash_t *dev, uint32_t saddr);


//
// 标准 FatFS-Disk-IO APIs
//
DSTATUS ffdisk_spiflash_init  (ffdisk_t *disk);
DSTATUS ffdisk_spiflash_status(ffdisk_t *disk);
DRESULT ffdisk_spiflash_read  (ffdisk_t *disk, BYTE *buff, LBA_t sector, UINT count);
DRESULT ffdisk_spiflash_write (ffdisk_t *disk, const BYTE *buff, LBA_t sector, UINT count);
DRESULT ffdisk_spiflash_ioctl (ffdisk_t *disk, BYTE cmd, void *buff);


#ifdef __cplusplus
}
#endif
